package com.smedi.ismedi.organization.core.domain.service.impl;

import com.smedi.ismedi.organization.core.domain.aggregatemodel.HrOrganization;
import com.smedi.ismedi.organization.core.domain.aggregatemodel.ProjectOrganization;
import com.smedi.ismedi.organization.core.domain.repository.ProjectOrganizationRepository;
import com.smedi.ismedi.organization.core.domain.service.ProjectOrganizationDomainService;
import com.smedi.ismedi.organization.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.organization.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.organization.core.infrastructure.enumerate.ProjectOrganizationTypeEnum;
import com.smedi.ismedi.organization.core.infrastructure.enumerate.SpecialTypeEnum;
import com.smedi.ismedi.organization.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.web.starter.exception.LogicException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Slf4j
@Service
@AllArgsConstructor
public class ProjectOrganizationDomainServiceImpl implements ProjectOrganizationDomainService {
    private final ProjectOrganizationRepository projectOrganizationRepository;

    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;

    /**
     * 生成默认的组织排序
     *
     * @param parentId
     * @return
     */
    private Integer generateDisplayOrder(Long parentId) {
        List<ProjectOrganization> projectOrganizations = projectOrganizationRepository.selectByParentId(parentId);
        Optional<ProjectOrganization> max = projectOrganizations.stream().max(Comparator.comparingLong(projectOrganization ->
                projectOrganization.getDisplayOrder() != null ? projectOrganization.getDisplayOrder() : 0L
        ));
        if (max.isPresent()) {
            return max.get().getDisplayOrder() != null ? (max.get().getDisplayOrder() + 1) : 0;
        } else {
            return 0;
        }
    }

    /**
     * 获取当前组织属于第几层级
     *
     * @param parentId
     * @return
     */
    private int getCurrentProjectOrganizationLevel(Long parentId) {
        int level = 0;
        ProjectOrganization projectOrganization = projectOrganizationRepository.selectByProjectOrganizationId(parentId);
        if (projectOrganization != null) {
            if (projectOrganization.getParentId() != null && !projectOrganization.isRoot()) {
                level += this.getCurrentProjectOrganizationLevel(projectOrganization.getParentId()) + 1;
            } else {
                level += 1;
            }
        } else {
            level += 1;
        }
        return level;
    }

    /**
     * 判断父级组织类型是否符合业务
     *
     * @param parent
     * @param current
     */
    private void validateParentProjectOrganization(ProjectOrganization parent, ProjectOrganization current) {
        // 判断上级组织的项目id是否与目标的项目id一致
        if (!current.getProjectId().equals(parent.getProjectId())) {
            throw LogicException.raise(CustomError.PARENT_ORG_NOT_BELONG_PROJECT);
        }
        // 新增组织权限判断
        if (ProjectOrganizationTypeEnum.ORGANIZATION_UNIT.getValue().equals(parent.getType())) {
            // 本单位下新增部门
            if (!ProjectOrganizationTypeEnum.DEPARTMENT.getValue().equals(current.getType())) {
                throw LogicException.raise(CustomError.PROJECT_ORG_CREATE_ERROR1);
            }
        } else if (ProjectOrganizationTypeEnum.EXTERNAL_UNIT.getValue().equals(parent.getType())) {
            // 外单位下新增部门
            if (!ProjectOrganizationTypeEnum.DEPARTMENT.getValue().equals(current.getType())) {
                throw LogicException.raise(CustomError.PROJECT_ORG_CREATE_ERROR2);
            }
        } else if (ProjectOrganizationTypeEnum.DEPARTMENT.getValue().equals(parent.getType())) {
            // 部门下新增部门
            if (!ProjectOrganizationTypeEnum.DEPARTMENT.getValue().equals(current.getType())) {
                throw LogicException.raise(CustomError.PROJECT_ORG_CREATE_ERROR3);
            }
        }
        // 判断当前父节点组织是否是当前组织的下属组织
        if (current != null) {
            List<ProjectOrganization> list = this.getProjectOrganizationChildrenByList(current.getProjectOrganizationId()); // 获取当前组织下的所有子节点，主要应对更新，一般新增不会有这块问题
            Optional<ProjectOrganization> optional = list.stream().filter(i -> i.getProjectOrganizationId().equals(parent.getProjectOrganizationId())).findFirst();
            if (optional.isPresent()) {
                throw LogicException.raise(CustomError.PARENT_ORG_CANNOT_BE_SON_NODE);
            }
        }
    }

    @Override
    public ProjectOrganization save(ProjectOrganization data) {
        ProjectOrganization basic;
        if (data.getProjectOrganizationId() != null) {
            basic = projectOrganizationRepository.selectByProjectOrganizationId(data.getProjectOrganizationId());
            if (basic == null) {
                throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_NOT_EXIST);
            } else {
                basic.setDisplayOrder(data.getDisplayOrder());
            }
        } else {
            basic = new ProjectOrganization()
                    .setDisplayOrder(generateDisplayOrder(data.getParentId()));
        }

        // 判断当前项目是否存在
        if (data.getProjectId() != null) {
            if (!constructionProjectRemoteApiService.checkProjectAvailable(data.getProjectId())) {
                throw LogicException.raise(CustomError.PROJECT_NOT_AVAILABLE);
            }
        } else {
            throw LogicException.raise(CustomError.PROJECT_ID_MISS);
        }

        // 判断项目组织是否被挂到了标段配置上，如果被使用，需要查看当前组织类型：本单位、外部单位
        if (data.getProjectOrganizationId() != null) {
            if (constructionProjectRemoteApiService.checkProjectOrganizationBeUsedInBiSection(data.getProjectOrganizationId())) {
                if (!ProjectOrganizationTypeEnum.ORGANIZATION_UNIT.getValue().equals(data.getType()) && !ProjectOrganizationTypeEnum.EXTERNAL_UNIT.getValue().equals(data.getType())) {
                    throw LogicException.raise(CustomError.PROJECT_ORG_TYPE_ERROR_BY_BID_SECTION);
                }
            }
        }

        // 本单位、外部单位必须维护组织特性，其他组织不允许维护
        if (ProjectOrganizationTypeEnum.ORGANIZATION_UNIT.getValue().equals(data.getType()) || ProjectOrganizationTypeEnum.EXTERNAL_UNIT.getValue().equals(data.getType())) {
            if (StringUtils.isEmpty(data.getSpecialType())) {
                throw LogicException.raise(CustomError.SPECIAL_TYPE_MISS);
            }
        } else {
            if (!StringUtils.isEmpty(data.getSpecialType())) {
                throw LogicException.raise(CustomError.SPECIAL_TYPE_ERROR);
            }
        }

        basic.setOrganizationCode(data.getOrganizationCode())
                .setFullName(data.getFullName())
                .setShortName(data.getShortName())
                .setType(data.getType())
                .setProjectId(data.getProjectId())
                .setSpecialType(data.getSpecialType())
                .setSocialCreditCode(data.getSocialCreditCode());

        // 判断组织全称是否重复
        if (duplicateFullName(basic.getFullName(), basic.getProjectOrganizationId(), basic.getProjectId())) {
            throw LogicException.raise(CustomError.ORG_FULL_NAME_DUPLICATE);
        }
        // 判断组织简称是否重复
        if (duplicateShortName(basic.getShortName(), basic.getProjectOrganizationId(), basic.getProjectId())) {
            throw LogicException.raise(CustomError.ORG_SHORT_NAME_DUPLICATE);
        }
        // 判断组织编码是否重复
        if (duplicateCode(basic.getOrganizationCode(), basic.getProjectOrganizationId(), basic.getProjectId())) {
            throw LogicException.raise(CustomError.ORG_CODE_DUPLICATE);
        }

        // 组织层级限制10层
        if (this.getCurrentProjectOrganizationLevel(data.getParentId()) > ConstantField.maxOrganizationLevel) {
            throw LogicException.raise(CustomError.ORG_MAX_LEVEL_ERROR);
        }

        // 判断父节点组织是否存在，如果不存在则显示报错
        if (data.getParentId() != null) {
            if (data.getProjectOrganizationId() != null) {
                if (data.getProjectOrganizationId().equals(data.getParentId())) {
                    throw LogicException.raise(CustomError.PARENT_ORG_MYSELF_WRONG);
                }
            }
            ProjectOrganization parent = projectOrganizationRepository.selectByProjectOrganizationId(data.getParentId());
            if (parent == null) {
                throw LogicException.raise(CustomError.PARENT_ORG_NOT_EXIST);
            } else {
                validateParentProjectOrganization(parent, data);
            }

            basic.setParentId(data.getParentId())
                    .setRoot(false);
        } else {
            // 表示自己是一个根
            basic.setRoot(true);
        }

        // 保存数据
        ProjectOrganization domain = (data.getProjectOrganizationId() == null) ? projectOrganizationRepository.doInsert(basic) : projectOrganizationRepository.doUpdate(basic);
        // 赋值数据
        domain.setTypeMeaning(ProjectOrganizationTypeEnum.getName(domain.getType()))
                .setSpecialTypeMeaning(SpecialTypeEnum.getName(domain.getSpecialType()));
        return domain;
    }

    @Override
    public List<ProjectOrganization> queryAll() {
        return projectOrganizationRepository.queryAll();
    }

    @Override
    public void delete(Long projectOrganizationId) {
        ProjectOrganization basic = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        if (basic == null) {
            throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_NOT_EXIST);
        }

        // 判断项目组织下是否有人员分配
        if (constructionProjectRemoteApiService.validateProjectOrganizationHasProjectAssignment(projectOrganizationId)) {
            throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_HAS_ASSIGNMENT);
        }

        // 判断组织下是否挂了子组织
        List<ProjectOrganization> list = this.getProjectOrganizationChildrenByList(projectOrganizationId);
        if (list.size() > 0) {
            throw LogicException.raise(CustomError.ORG_DELETE_FAILED_BY_HAS_CHILDREN);
        }

        // 执行删除
        projectOrganizationRepository.doDelete(basic);
    }

    @Override
    public List<ProjectOrganization> getProjectOrganizationChildrenByList(Long projectOrganizationId) {
        Set<ProjectOrganization> set = new HashSet<>();
        ProjectOrganization basic = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        if (basic != null) {
            // 获取当前节点下的组织信息
            List<ProjectOrganization> nodes = projectOrganizationRepository.selectByParentId(basic.getProjectOrganizationId());
            for (ProjectOrganization i : nodes) {
                i.setTypeMeaning(ProjectOrganizationTypeEnum.getName(i.getType())) // 组织类型
                        .setSpecialTypeMeaning(SpecialTypeEnum.getName(i.getSpecialType())) // 组织特性
                        .setParentFullName(basic.getFullName())   // 上级组织名称
                        .setParentShortName(basic.getShortName());   // 上级组织名称
                set.add(i); // 添加自身组织
                if (i.getProjectOrganizationId() != null) {
                    set.addAll(getProjectOrganizationChildrenByList(i.getProjectOrganizationId()));
                }
            }
        }

        return new ArrayList<>(set);
    }

    @Override
    public List<ProjectOrganization> getProjectOrganizationChildrenByTree(Long projectOrganizationId) {
        List<ProjectOrganization> list = new ArrayList<>();
        ProjectOrganization basic = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        if (basic != null) {
            // 获取当前节点下的组织信息
            List<ProjectOrganization> nodes = projectOrganizationRepository.selectByParentId(basic.getProjectOrganizationId());
            for (ProjectOrganization i : nodes) {
                i.setTypeMeaning(ProjectOrganizationTypeEnum.getName(i.getType())) // 组织类型
                        .setSpecialTypeMeaning(SpecialTypeEnum.getName(i.getSpecialType())) // 组织特性
                        .setParentFullName(basic.getFullName())   // 上级组织名称
                        .setParentShortName(basic.getShortName());   // 上级组织名称
                // 添加子组织
                if (i.getProjectOrganizationId() != null) {
                    i.setProjectOrganizationChildren(getProjectOrganizationChildrenByTree(i.getProjectOrganizationId()));
                }
                list.add(i); // 添加自身组织
            }
        }
        return list;
    }

    @Override
    public Boolean validateProjectOrganization(Long projectOrganizationId) {
        ProjectOrganization projectOrganization = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        return (projectOrganization != null);
    }

    @Override
    public Boolean duplicateFullName(String fullName, Long projectOrganizationId, Long projectId) {
        return projectOrganizationRepository.selectFullNameCount(fullName, projectOrganizationId, projectId) > 0;
    }

    @Override
    public Boolean duplicateShortName(String shortName, Long projectOrganizationId, Long projectId) {
        return projectOrganizationRepository.selectShortNameCount(shortName, projectOrganizationId, projectId) > 0;
    }

    @Override
    public Boolean duplicateCode(String code, Long projectOrganizationId, Long projectId) {
        return projectOrganizationRepository.selectOrganizationCodeCount(code, projectOrganizationId, projectId) > 0;
    }

    @Override
    public Boolean validateProjectOrganizationCanBeConfigOrg(Long projectOrganizationId) {
        ProjectOrganization projectOrganization = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        if (projectOrganization != null) {
            // 只有”本单位“、“外部单位”可作为配置项组织
            return (ProjectOrganizationTypeEnum.ORGANIZATION_UNIT.getValue().equals(projectOrganization.getType()) || ProjectOrganizationTypeEnum.EXTERNAL_UNIT.getValue().equals(projectOrganization.getType()));
        } else {
            return false;
        }
    }

    // 获取所有父节点组织
    private List<ProjectOrganization> getAllOrganizationParents(ProjectOrganization projectOrganization, boolean containCurrent) {
        List<ProjectOrganization> parents = new ArrayList<>();
        if (containCurrent) {
            parents.add(projectOrganization);
        }
        if (projectOrganization.getParentId() != null) {
            ProjectOrganization parent = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganization.getParentId());
            if (parent != null) {
                parents.add(parent);
                parents.addAll(this.getAllOrganizationParents(parent, false));
            }
        }
        return parents;
    }

    @Override
    public Boolean validateProjectOrganizationIsExternalUnit(Long projectOrganizationId) {
        ProjectOrganization projectOrganization = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        if (projectOrganization != null) {
            // 从当前节点反爬所有父组织，只要有一个是外部单位则不符合要求
            List<ProjectOrganization> parents = getAllOrganizationParents(projectOrganization, true);
            Optional<ProjectOrganization> result = parents.stream().filter(i -> ProjectOrganizationTypeEnum.EXTERNAL_UNIT.getValue().equals(i.getType())).findFirst();
            return result.isPresent();
        } else {
            return false;
        }
    }

    @Override
    public ProjectOrganization getProjectOrganizationByProjectOrganizationId(Long projectOrganizationId) {
        ProjectOrganization projectOrganization = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        return projectOrganization;
    }

    @Override
    public void saveProjectOrganizationDisplayOrder(Long projectOrganizationId, Integer displayOrder) {
        ProjectOrganization basic = projectOrganizationRepository.selectByProjectOrganizationId(projectOrganizationId);
        if (basic == null) {
            throw LogicException.raise(CustomError.PROJECT_ORGANIZATION_NOT_EXIST);
        }

        if (displayOrder == null) {
            throw LogicException.raise(CustomError.DISPLAY_ORDER_MISS);
        }
        basic.setDisplayOrder(displayOrder);
        projectOrganizationRepository.doUpdate(basic);
    }
}
